local floor = math.floor
local select = select
local tinsert = table.insert
local format = format
local strfind = strfind
local strsub = string.sub
local gsub = string.gsub
local gmatch = string.gmatch
local strlen = string.len
local match = string.match
local find = string.find
local abs = math.abs

local SMALL_GOLD_ICON   = "|TInterface\\MoneyFrame\\UI-GoldIcon:12:12:2:0|t"
local SMALL_SILVER_ICON	= "|TInterface\\MoneyFrame\\UI-SilverIcon:12:12:2:0|t"
local SMALL_COPPER_ICON	= "|TInterface\\MoneyFrame\\UI-CopperIcon:12:12:2:0|t"

local LARGE_GOLD_ICON   = "%02d\124TInterface\\MoneyFrame\\UI-GoldIcon:12:12:2:0\124t"
local LARGE_SILVER_ICON = "%02d\124TInterface\\MoneyFrame\\UI-SilverIcon:12:12:2:0\124t"
local LARGE_COPPER_ICON = "%02d\124TInterface\\MoneyFrame\\UI-CopperIcon:12:12:2:0\124t"

local GLYPH_PREFIX      = 'Glyph of '
local GLYPH_MATCH       = 'Glyph of (.+)'

local function MatchTemplate(template, str)
   if str == nil then
      return
   end
   
   -- local ret = match(str, template)
   -- print('ret: ', ret)
   -- return ret
   
   local loc = strfind(template, "%s", 1, true);
   local front = strsub(template, 1, loc - 1);
   local back = strsub(template, loc + 2);

   local matchfront = (strsub(str, 1, strlen(front)) == front);
   local matchback = (strsub(str, strlen(str) - strlen(back) + 1) == back);

   return (matchfront and matchback);
end

function ToGSC(v)
   local negative = v < 0
	local rv = abs(floor(v + 0.5))
	local g = floor(rv / 10000);  rv = rv - g*10000;
	local s = floor(rv / 100);    rv = rv - s*100;
	local c = rv;
	return g, s, c, negative
end

function Spy.GetMoneyString(money, noicon)
   local gold, silver, copper, negative = ToGSC(money)
   local st = ""
   
   local goldicon, silvericon, coppericon
   
   if noicon then
      goldicon, silvericon, coppericon = ' G, ', ' S, ', ' C'
   else
      goldicon, silvericon, coppericon = SMALL_GOLD_ICON, SMALL_SILVER_ICON, SMALL_COPPER_ICON
   end
   
   if gold ~= 0 then
      st = st..gold..goldicon.."  "
   end
   
   if st ~= "" then
      st = st..format("%02i%s  ", silver, silvericon)
   elseif silver ~= 0 then
      st = st..silver..silvericon.."  "
   end
   
   if st ~= "" then
      st = st..format("%02i%s", copper, coppericon)
   else--if copper ~= 0 then
      st = st..copper..coppericon
   end
   
   if negative then st = "-"..st end
   
   return st
end

function Spy.GetMoneyStringLarge(money)
   local g, s, c, negative = ToGSC(money)
   local str = ""
   if negative then str = "-" end
   if g > 0 then str = str .. format(LARGE_GOLD_ICON, g).."  " end
   if s > 0 then str = str .. format(LARGE_SILVER_ICON, s).."  " end
   return str .. format(LARGE_COPPER_ICON, c)
end

function Spy.GetMoneyStringColored(money, abrv)
   local gColor, sColor, cColor =
      RGBToStr(255, 230, 0),
      RGBToStr(220, 220, 220),
      RGBToStr(210, 130, 0)
      
   local g, s, c, neg = ToGSC(money)
   
   local gAbrv, sAbrv, cAbrv = '', '', ''
   if abrv then
      gAbrv, sAbrv, cAbrv = 'g', 's', 'c'
   end
   
   local str = ""
   local fmt = '%s%5d%s  '
   
   if neg then
      if g>0 then g=-g
      elseif s>0 then s=-s
      else c=-c
      end
   end
   
   if g~=0 then
      str=str..format(fmt, gColor, g, gAbrv)
      str=str..format(fmt, sColor, s, sAbrv)
   elseif s~=0 then
      str=str..format(fmt, sColor, s, sAbrv)
   end
   
   return str..format(fmt, cColor, c, cAbrv)
end

local historyTemplate =
{
   'numSold',
   'totalEarned',
   'numBought',
   'totalSpent',
   'numExpired',
   'recentSold',
   'recentExpired',
}

function Spy.ConvertAuctionHistory(history)
   local newHistory = {}
   for k, v in pairs(history) do
      newHistory[k] = {v.numSold, v.totalEarned, v.numBought, v.totalSpent, v.numExpired}
   end
   return newHistory
end

function Spy.GetAuctionHistory(item)
   local data = SpyAuctionHistory[item]
   if not data then data = {} end
   local history = {}
   for i,v in ipairs(historyTemplate) do
      history[v] = data[i] or 0
   end
   history.item = item
   
   return history
end

function Spy.SaveAuctionHistory(history)
   local data = SpyAuctionHistory[history.item]
   if not data then
      data = {}
      SpyAuctionHistory[history.item] = data
   end
   for i,v in ipairs(historyTemplate) do
      data[i] = history[v]
   end
end

function Spy.GetGlyphName(glyph)
   return glyph:match(GLYPH_PREFIX..'(.+)')
end

function Spy.IsGlyph(item)
   return Spy.GetGlyphName(item) ~= nil
end

function Spy.GotMoneyInMail(index)
   local packageIcon, stationeryIcon, sender, subject, money, CODAmount,
      daysLeft, hasItem, wasRead, wasReturned,
      textCreated, canReply, isGM = GetInboxHeaderInfo(index);

   local auctiontext = AUCTION_SOLD_MAIL_SUBJECT;
   --local subject = OpenMailSubject:GetText();

   local loc = strfind(auctiontext, "%s", 1, true);
   local front = strsub(auctiontext, 1, loc - 1);
   local back = strsub(auctiontext, loc + 2);

   if subject == nil then
      print("Subject was null")
      return
   end

   if (MatchTemplate(auctiontext, subject)) then
      local itemSold = gsub(subject, front.."(.+)"..back, "%1")
      local history = Spy.GetAuctionHistory(itemSold)
      history.numSold = history.numSold + 1
      history.totalEarned = history.totalEarned + money
      history.recentSold = history.recentSold + 1
      Spy.SaveAuctionHistory(history)
   else
      print("Could not find auction history!")
   end
end

function Spy.GotItemInMail(index, itemindex)
   local item, texture, count, quality, canUse = GetInboxItem(index, itemindex)
   local subject = OpenMailSubject:GetText()
   -- print(subject)
   -- print(item, texture, count, quality, canUse)
   
   -- or MatchTemplate('Auction cancelled: %s', subject)

   if MatchTemplate(AUCTION_WON_MAIL_SUBJECT, subject) then
      local history = Spy.GetAuctionHistory(item)
      history.numBought = history.numBought + count
      Spy.SaveAuctionHistory(history)
   elseif MatchTemplate(AUCTION_EXPIRED_MAIL_SUBJECT, subject) then
      local history = Spy.GetAuctionHistory(item)
      history.numExpired = history.numExpired + count
      history.recentExpired = history.recentExpired + 1
      Spy.SaveAuctionHistory(history)
   end
end

OldTakeInboxMoney = TakeInboxMoney
TakeInboxMoney = function(index)
   OldTakeInboxMoney(index)
   Spy.GotMoneyInMail(index)
end

OldTakeInboxItem = TakeInboxItem
TakeInboxItem = function(index, itemindex)
   OldTakeInboxItem(index, itemindex)
   Spy.GotItemInMail(index, itemindex)
end

-------------------------------------------------------------------------------
function Spy.CancelAllAuctions()
   local numAuctions = GetNumAuctionItems("owner")
   for i=1, GetNumAuctionItems("owner") do
      CancelAuction(i)
   end
   Spy.DebugPrint("All Auctions Canceled")
end

function Spy.CancelAuctions(toCancel)
   for i=1, GetNumAuctionItems('owner') do
      local auction = GetAuctionItemInfo('owner', i)
      if toCancel[auction] ~= nil then
         CancelAuction(i)
      end
   end
end

local b = CreateFrame("Button", "SpyCancelAuctions", UIParent, "OptionsButtonTemplate")
b:SetText("Cancel All")
b:SetPoint("TOPLEFT", UIParent, 10, -80)
b:SetWidth(120)
b:SetScript("OnClick", Spy.CancelAllAuctions)
b:Hide()

-------------------------------------------------------------------------------
local events = {}

function events:PLAYER_MONEY()
   local cur = GetMoney()
   
   if SpyDB.bLogMoney then
      local dif = cur - money
      local moneyStr = Spy.GetMoneyString(abs(dif))
      
      if dif > 0 then
         printf("+ %s", moneyStr)
      elseif dif < 0 then
         printf("- %s", moneyStr)
      end
   end
   
   money = cur
end

function events:PLAYER_ENTERING_WORLD()
   money = GetMoney()
end

function events:AUCTION_HOUSE_SHOW()
   SpyCancelAuctions:SetParent(AuctionFrameAuctions)
   SpyCancelAuctions:Show()
   --print("Showing cancel auctions button");
end

function events:AUCTION_HOUSE_CLOSED()
   SpyCancelAuctions:Hide()
end

AddEventListeners(events)

local ENTRY_COLOR = {1, 1, 0.5, 1, 1, 1}

local function AddSellRatio(tooltip, sold, expired)
   local total = sold + expired
   if total > 0 then
      local ratio = sold / total
      tooltip:AddDoubleLine('Sold', format('%d / %d', sold, total), unpack(ENTRY_COLOR))
      tooltip:AddDoubleLine('Ratio', format('%d', round(ratio*1000)), 1, 1, 0.5, GetPctColor(ratio*2))
   end
end

local function AddAuctionInfo(tooltip, ...)
   local item = tooltip:GetItem()
   if item == nil then return end
   local history = Spy.GetAuctionHistory(item)
   if history then
      local total = history.numSold + history.numExpired
      local ratio = 0
      if total > 0 then
         tooltip:AddLine(" ")
         if history.numSold > 0 or history.numExpired > 0 then
            local avg = 0
            if history.numSold > 0 then
               avg = history.totalEarned/history.numSold
            end
            local avgGold = ToGSC(avg)
            local scolor = {1, 0, 0}
            
            if avgGold >= 20 then       scolor = {0, 1.0, 0}
            elseif avgGold >= 14 then   scolor = {0.5, 1.0, 0.5}
            elseif avgGold >= 10 then    scolor = {1, 1, 0}
            elseif avgGold >= 5 then    scolor = {1, 0.5, 0}
            else                       scolor = {1, 0, 0}
            end
            
            local avgcolor = {1, 1.0, 0.5, unpack(scolor)}
            
            tooltip:AddDoubleLine('Earned', Spy.GetMoneyString(history.totalEarned), unpack(ENTRY_COLOR))
            tooltip:AddDoubleLine('Avg', Spy.GetMoneyString(avg), unpack(avgcolor))
            AddSellRatio(tooltip, history.numSold, history.numExpired)
            -- if (history.recentSold + history.recentExpired) > 0 then
               -- tooltip:AddLine(' ')
               -- tooltip:AddLine('Recent')
               -- AddSellRatio(tooltip, history.recentSold, history.recentExpired)
            -- end
         end
         tooltip:AddLine(" ")
      end
   end
end

HookTooltip('OnTooltipSetItem', AddAuctionInfo)

function Spy.CullNonGlyphs(history)
   local numCulled = 0
   for k, v in pairs(history) do
      if select(6, GetItemInfo(k)) ~= 'Glyph' then
         history[k] = nil
         numCulled = numCulled + 1
      end
   end
   print("numCulled: "..numCulled)
end

function Spy.CreateAuctionTable()
   if Spy.auctionTable then return end
   local cols =
   {
      {
         name = "Name",
         width = 100,
         bgcolor = {.2, .2, .2}
      }
   }
   
   for i,v in pairs(historyTemplate) do
      local col = {}
      col.name = v
      col.width = 80
      col.bgcolor = {0, 0, 0}
      tinsert(cols, col)
   end

   Spy.auctionTable = LibStub('ScrollingTable'):CreateST(cols, 20)
   MakeFrameDraggable(Spy.auctionTable.frame)
end

function Spy.ToggleAuctionTable()
   if not Spy.auctionTable then
      Spy.CreateAuctionTable()
   end
   Toggle(Spy.auctionTable)
end

--AddEventListener('PLAYER_LOGIN', Spy.CreateAuctionTable)
-- local b = Spy.CreateButton('Auction History', Spy.CreateAuctionTable, UIParent, 'SpyShowAuctionHistory')
-- b:SetPoint('TOPLEFT', 0, 0)






